#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>

namespace BlockQueueModule
{
    const int gcap = 10;
    template<typename T>
    class BlockQueue
    {
    private:
        bool IsFull() { return _bq.size() == _capacity; }
        bool IsEmpty() { return _bq.empty(); }
    public:
        BlockQueue(int capacity = gcap):_capacity(capacity),_consumer_wait_num(0), _producer_wait_num(0)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_consumer_cond, nullptr);
            pthread_cond_init(&_producer_cond, nullptr);
        }
        void PushQueue(const T& in)
        {
            pthread_mutex_lock(&_mutex);
            //如果阻塞队列为满，就让生产者去等待
            while(IsFull())
            {
                _producer_wait_num++;
                printf("生产者进入等待1...\n");
                pthread_cond_wait(&_producer_cond, &_mutex); //可能会出现伪唤醒问题，所以判断语句把if改成while可以有效避免：无论因为啥被唤醒都再次检测条件是否满足
                printf("生产者被唤醒1...\n");
                _producer_wait_num--;
            }
            _bq.push(in);
            //阻塞队列肯定不为空，判断是否有消费者线程在等待，有就唤醒
            if(_consumer_wait_num > 0)
            {
                printf("消费者被唤醒1...\n");
                pthread_cond_signal(&_consumer_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }
        void PopQueue(T* out)
        {
            pthread_mutex_lock(&_mutex);
            //如果阻塞队列为空，就让消费者去等待
            while(IsEmpty())
            {
                _consumer_wait_num++;
                printf("消费者进入等待2...\n");
                pthread_cond_wait(&_consumer_cond, &_mutex);
                printf("消费者被唤醒2...\n");
                _consumer_wait_num--;
            }
            *out = _bq.front();
            _bq.pop();
            //阻塞队列肯定不为满，判断是否有生产者线程在等待，有就唤醒
            if(_producer_wait_num > 0)
            {
                printf("生产者被唤醒2...\n");
                pthread_cond_signal(&_producer_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }
        ~BlockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_consumer_cond);
            pthread_cond_destroy(&_producer_cond);
        }
    private:
        std::queue<T> _bq;                //阻塞队列
        int _capacity;                    //阻塞队列的最大容量
        pthread_mutex_t _mutex;           //保证生产者和消费者互斥的锁
        pthread_cond_t _consumer_cond;    //消费者的条件变量
        pthread_cond_t _producer_cond;    //生产者的条件变量
        int _consumer_wait_num;           //等待的消费者数量
        int _producer_wait_num;           //等待的生产者数量
    };
}